package glossos.parsing;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import static org.mockito.Mockito.verify;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Arrays;
import java.util.Observer;

@RunWith(MockitoJUnitRunner.class)
public class WordBufferTestCase {
    WordBuffer buffer;
    @Mock Observer observerMock;

    @Before
    public void setUp(){
        buffer = new WordBuffer();
        buffer.addObserver(observerMock);
    }

    @Test
    public void stringRepresentationIsConcatenatedChars() {
        appendChars('b', 'e', 'e', 'r');
        assertThat(buffer.toString(), is("beer"));
    }

    @Test
    public void callFlushAfterNormalAppends() {
        appendCharsAndGroup('I');
        appendCharsAndGroup('l', 'o', 'v', 'e');
        appendCharsAndGroup('b', 'e', 'e', 'r');
        buffer.flush();
        
        verify(observerMock).update(buffer, Arrays.asList("I", "love", "beer"));
    }

    @Test
    public void sendNullMessageWhenClosed() {
        buffer.close();
        verify(observerMock).update(buffer, null);
    }

    @Test
    public void callFlushAfterBothTypesOfAppend() {
        appendCharsAndGroup('I');
        appendCandidateChars('l', 'o');
        appendCharsAndGroup('v', 'e');
        appendCharsAndGroup('b', 'e', 'e', 'r');
        buffer.flush();
        
        verify(observerMock).update(buffer, Arrays.asList("I", "love", "beer"));
    }

    @Test
    public void releasedCandidatesNotIncludedInList() {
        appendCharsAndGroup('I');
        appendCandidateChars('l', 'o');
        buffer.releaseCandidates();
        appendCharsAndGroup('v', 'e');
        appendCharsAndGroup('b', 'e', 'e', 'r');
        buffer.flush();
        
        verify(observerMock).update(buffer, Arrays.asList("I", "ve", "beer"));
    }

    private void appendCharsAndGroup(Character...chars){
        appendChars(chars);
        buffer.group();
    }

    private void appendChars(Character...chars){
        for (Character character : chars)
            buffer.append(character);
    }
    
    private void appendCandidateChars(Character...chars){
        for (Character character : chars)
            buffer.appendCandidate(character);
    }
}
